#[cfg(feature = "acpi")]
use super::device::hpet;
use super::device::pit;

pub fn counter() -> u128 {
    #[cfg(feature = "acpi")]
    if let Some(ref hpet) = *crate::acpi::ACPI_TABLE.hpet.read() {
        //TODO: handle rollover?
        //TODO: improve performance

        // Current count
        let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
        // Comparator holds next interrupt count
        let comparator = unsafe { hpet.base_address.read_u64(hpet::T0_COMPARATOR_OFFSET) };
        // Get period in femtoseconds
        let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };

        // There seems to be a bug in qemu on macos that causes the calculation to produce 0 for
        // period_fs and hence a divide by zero calculating the divisor - workaround it while we
        // try and get a fix from qemu: https://gitlab.com/qemu-project/qemu/-/issues/1570
        let mut period_fs = capability >> 32;
        if period_fs == 0 {
            period_fs = 10_000_000;
        }

        // Calculate divisor
        let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
        // Calculate last interrupt
        let last_interrupt = comparator.saturating_sub(divisor);
        // Calculate ticks since last interrupt
        let elapsed = counter.saturating_sub(last_interrupt);
        // Calculate nanoseconds since last interrupt
        return (elapsed as u128 * period_fs as u128) / 1_000_000;
    }

    // Read ticks since last interrupt
    let elapsed = unsafe { pit::read() };
    // Calculate nanoseconds since last interrupt
    (elapsed as u128 * pit::PERIOD_FS) / 1_000_000
}
